#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/7/26 17:27
# @Author  : 王凯
# @File    : company_search_parser_gsxt.py
# @Project : scrapy_spider
import decimal
import logging as logger
import re
import time
from functools import reduce

import parsel


class CompanySearchGsxtParser(object):
    def __init__(self, all_data, logger_cls=None, **kwargs):
        self.base_url = kwargs.get("base_url") or "https://www.gsxt.gov.cn"
        self.all_data = all_data
        self.all_result = {}
        self.log = logger_cls or logger

    def parse_home(self):
        self.log.info("准备解析主页... ")
        card_pages = [i for i in self.all_data if i.get("url") == f"{self.base_url}/corp-query-search-1.html"]
        history_names = []
        corp_status = None
        home_url = None
        if card_pages:
            card_page = card_pages[0]["text"]
            response = parsel.Selector(text=card_page)
            cards = response.xpath("//*[contains(@class, 'search_list_item')]")
            if cards:
                card = cards[0]
                if card:
                    history_name = card.xpath("string()").re_first(r"历史名称[:：]\s*([^\s]*)")
                    corp_status = (card.xpath("string(//div[@class='wrap-corpStatus'])").get() or "").strip()
                    home_url = (card.xpath("./@href").get() or "").replace("javascript:void(0)", "")
                    if history_name:
                        history_names = history_name.split("；")
            self.all_result["history_names"] = history_names
            self.all_result["corp_status"] = corp_status
        home_pages = [i for i in self.all_data if i.get("url") == f"{self.base_url}{home_url}"]
        if home_pages:
            home_page = home_pages[0]["text"]
            url_mapping = {k: self.base_url + v for k, v in re.findall(r"var\s+(.*?)\s*=\s*\"(.*?)\"\s*", home_page)}
            base_info = self._parse_base(home_page)
            corp_status = corp_status or base_info.get("operating_status")
            self.all_result["corp_status"] = corp_status
            self.all_result["base_info"] = {**base_info, **{"history_names": history_names}}
            self.log.info("主页解析完成，准备解析子项...")
            shareholder_detail_mapping = self._parse_shareholder_detail()
            shareholder_nb_mapping = self._parse_shareholder_by_nb()
            for name, url in url_mapping.items():
                if name in ["shareholderUrl", "alterInfoUrl", "anCheYearInfo", 'gtAlertInfoUrl']:
                    _name = name.replace("Url", "")
                    _pages = [i for i in self.all_data if i.get("url") == url and i.get("json")]
                    self.all_result.update(self._parse_other(name=_name, pages=_pages))
            if "shareholder" in self.all_result:
                all_details_money = sum([i["shouldCapi"] for i in shareholder_detail_mapping.values()])
                for i in self.all_result["shareholder"]:
                    detail = shareholder_detail_mapping.get(i["invId"], {})
                    detail, all_details_money = self._merge_shareholder_percent(
                        item=i, extend=detail, all_details_money=all_details_money
                    )
                    if detail.get("shouldCapi"):
                        detail["percent"] = float(
                            round(decimal.Decimal(detail["shouldCapi"] / all_details_money) * 100, ndigits=4)
                        )
                    else:
                        detail["percent"] = None
                    i.update(detail)
            if "anCheYearInfo" in self.all_result:
                # 年报的股东数据
                for i in self.all_result["anCheYearInfo"]:
                    sponsor = shareholder_nb_mapping.get(i["anCheId"], [])
                    sponsor = self._merge_shareholder_nb_percent(sponsor)
                    i.update({"sponsor": sponsor})  # 年报数据
            self.log.info("子项解析完成，保存...")
            return self.all_result
        else:
            if corp_status and not home_url:
                self.log.info("不存在主页,但存在搜索结果,解析完成")
                return self.all_result
            else:
                self.log.info("不存在主页...")
                return self.all_result

    def parser_other_item(self, response_json):
        if isinstance(response_json, list):
            results = response_json
        else:
            results = response_json.get("data")
        if results:
            for i in results:
                if isinstance(i, dict):
                    for k, v in i.items():
                        if v:
                            if isinstance(v, str):
                                v = re.sub("(?i)<div(.|\n)*?</div>", "", v)  # (?)忽略大小写
                                v = re.sub("(?i)<span(.|\n)*?</span>", "", v)  # (?)忽略大小写
                                i.update({k: v.strip()})
                            if k in ["altDate", "anCheDate"] and v:  # 时间处理
                                i.update({k: self._change_timestamp_to_date(v)})
        return results

    def _parse_base(self, page):
        response = parsel.Selector(text=page)
        info = response.xpath('//*[@id="primaryInfo"]//dl')
        info_text = "|".join([re.sub("[\n\t\r]", "", i.xpath("string(.)").get() or "") for i in info])
        item = {
            "company_name": self.reg_one(r"[企业]*名称[：:]\s+([^|]*?)\s+", info_text).replace("（", "(").replace("）", ")"),
            "taxpayer_id": self.reg_one(r"统一社会信用代码[：:]\s+([^|]*?)\s+", info_text),
            "register_id": self.reg_one(r"注册号[：:]\s+([^|]*?)\s+", info_text),
            "register_address": self.reg_one(r"(?:经营场所|住所|营业场所)[：:]\s+([^|]*?)\s+", info_text),
            "update_month": self.reg_one(r"核准日期[：:]\s+([^|]*?)\s+", info_text),
            "register_capital_msg": self.reg_one(r"(?:注册资本|出资额)[：:]\s+([^|]*?)\s+", info_text) or None,
            "start_operation_date": self.reg_one(r"(?:营业|合伙)期限自[：:]\s+([^|]*?)\s+", info_text) or None,
            "end_operation_date": self.reg_one(r"(?:营业|合伙)至[：:]\s+([^|]*?)\s+", info_text) or None,
            "organization_type": self.reg_one(r"类型[：:]\s+([^|]*?)\s+", info_text),
            "legal_name": self.reg_one(r"(?:法定代表人|经营者|执行事务合伙人|负责人)[：:]\s+([^|]*?)\s+", info_text)
            .replace("（", "(")
            .replace("）", ")"),
            "operating_status": self.reg_one(r"登记状态[：:]\s+([^|]*?)\s+", info_text),
            "belong_org": self.reg_one(r"登记机关[：:]\s+([^|]*?)\s+", info_text),
            "business_scope": self.reg_one(r"经营范围[：:]\s+([^|]*?)\s+", info_text),
            "start_date": self.reg_one(r"(?:成立日期|注册日期)[：:]\s+([^|]*?)\s+", info_text) or None,
            "check_date": self.reg_one(r"核准日期[：:]\s+([^|]*?)\s+", info_text) or None,
        }
        try:
            register_capital_msg = item.get("register_capital_msg")
            register_capital = self.process_money(register_capital_msg)
            register_currencies = self.reg_one(r"([^\d.]+)", register_capital_msg)
            if register_capital and register_capital:
                item.update({"register_capital": register_capital})
                item.update({"register_currencies": register_currencies})
        except:
            pass
        return item

    def _parse_other(self, name, pages):
        """
        解析子项
        """
        other_data = None
        result_item = {}
        try:
            for i in pages:
                other_data = i.get("json")
                if name in result_item:  # 合并存在列表
                    result_item[name].extend(self.parser_other_item(other_data))
                else:
                    result_item[name] = self.parser_other_item(other_data)
            if result_item[name]:  # 去重列表
                result_item[name] = self.list_dict_duplicate_removal(result_item[name])
                pass
            if other_data:
                if isinstance(other_data, dict):
                    if other_data and (
                            other_data.get("recordsTotal") - 5 < len(result_item[name]) <= other_data.get("recordsTotal")
                    ):
                        result_item[name + "_records_total_src"] = other_data.get("recordsTotal")
                        result_item[name + "_records_total"] = len(result_item[name])
                        result_item[name + "_check"] = True
                    else:
                        result_item[name + "_records_total_src"] = (
                            other_data.get("recordsTotal") if other_data and other_data.get("recordsTotal") else None
                        )
                        result_item[name + "_records_total"] = len(result_item[name])
                        result_item[name + "_check"] = False
                    self.log.info(
                        f"子项恒等 {name} {result_item[name + '_check']} {len(result_item[name])} recordsTotal:{other_data.get('recordsTotal')}"
                    )
                else:
                    if name == "anCheYearInfo":  # 年报缩减字段
                        result_item[name] = [
                            {k: v for k, v in i.items() if k in ["anCheDate", "anCheYear", "anCheId", "pripId"]}
                            for i in result_item[name]
                        ]
                    self.log.info(f"该子项跳过恒等检查 {name}")
        except Exception as e:
            self.log.error(e)
        return result_item

    def _parse_shareholder_by_nb(self):
        result_item = {}
        _pages = [
            i
            for i in self.all_data
            if i.get("url").startswith(f"{self.base_url}/corp-query-entprise-info-sponsor-") and i.get("json")
        ]
        for page in _pages:
            anCheId = self.reg_one(
                rf"{self.base_url}/corp-query-entprise-info-sponsor-(.*?).html",
                page.get("url"),
            )
            ret = page.get("json").get("data")

            for i in ret:
                for k in ["subConDate", "acConDate"]:
                    if k in i:
                        i.update({k: self._change_timestamp_to_date(i[k])})
            result_item[anCheId] = ret
        return result_item

    def _parse_shareholder_detail(self):
        result_item = {}
        _pages = [
            i
            for i in self.all_data
            if i.get("url").startswith(f"{self.base_url}/corp-query-entprise-info-shareholderDetail") and i.get("json")
        ]
        for page in _pages:
            invId = self.reg_one(
                rf"{self.base_url}/corp-query-entprise-info-shareholderDetail-(.*?).html",
                page.get("url"),
            )
            ret = page.get("json").get("data")
            real = ret[0]
            should = ret[1]
            for i in real:
                if "conDate" in i:
                    i.update({"conDate": self._change_timestamp_to_date(i["conDate"])})
            for i in should:
                if "conDate" in i:
                    i.update({"conDate": self._change_timestamp_to_date(i["conDate"])})
            result_item[invId] = {
                "real": real,
                "should": should,
                "realCapi": sum([i["acConAm"] for i in real]),
                "shouldCapi": sum([i["subConAm"] for i in should]),
            }
        return result_item

    def _merge_shareholder_percent(self, item, extend=None, all_details_money=None):
        if "detailCheck" in item:  # 公示的股东信息
            if item["detailCheck"] == "false":
                if "liSubConAm" in item:
                    all_details_money = sum(
                        [j["liSubConAm"] for j in self.all_result["shareholder"] if j["liSubConAm"]]
                    )
                    extend["shouldCapi"] = item["liSubConAm"]
                else:
                    pass  # detail 中的shouldCapi
            else:  # 有详情
                if all_details_money == 0:
                    if "liSubConAm" in item:
                        all_details_money = sum(
                            [j["liSubConAm"] for j in self.all_result["shareholder"] if j["liSubConAm"]]
                        )
                        extend["shouldCapi"] = item["liSubConAm"]
                else:
                    pass  # detail 中的shouldCapi
        return extend, all_details_money

    def _merge_shareholder_nb_percent(self, items):
        # 年报的股东信息
        all_details_money = sum([i["liSubConAm"] for i in items])
        for item in items:
            if "liSubConAm" in item:
                item["shouldCapi"] = item["liSubConAm"]
            else:
                item["shouldCapi"] = None
            if item["shouldCapi"] is not None and all_details_money != 0:
                item["percent"] = float(round(decimal.Decimal(item["shouldCapi"] / all_details_money) * 100, ndigits=4))
            else:
                item["percent"] = None
        return items

    @staticmethod
    def _change_timestamp_to_date(sec):
        if sec:
            try:
                return time.strftime("%Y-%m-%d", time.localtime(sec / 1000))
            except Exception as e:
                return None

    @staticmethod
    def list_dict_duplicate_removal(data_list):
        return reduce(
            lambda x, y: x if y in x else x + [y],
            [
                [],
            ]
            + data_list,
        )

    @staticmethod
    def reg_one(regex, text):
        for reg in re.findall(regex, text):
            return reg
        return ""

    @staticmethod
    def process_money(amount: str) -> float:
        """
        金额转中文大写
        :param amount:
        :return:
        """
        # logger.debug(f"amount1,{amount}")
        if not amount:
            return float(0)
        # print(amount)
        amount = amount.replace("人民币", "")
        amount = amount.replace("美元", "")
        amount = amount.replace("元", "")
        amount = amount.replace(",", "")
        amount = amount.replace("，", "")
        # logger.debug(f"amount2,{amount}")
        try:
            if amount.endswith("万"):
                amount_an = decimal.Decimal(amount.replace("万", "")) * 10000
            elif amount.endswith("亿"):
                amount_an = decimal.Decimal(amount.replace("亿", "")) * 100000000
            else:
                amount_an = decimal.Decimal(amount)
        except Exception:
            amount_an = decimal.Decimal(0)
        amount_an = float(amount_an)
        # logger.debug(f"amount_an,{amount_an}")
        return amount_an
